home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / machine / polepos.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  11KB  |  461 lines

  1. #include "driver.h"
  2. #include "cpu/z80/z80.h"
  3.  
  4.  
  5. #define VERBOSE 0
  6.  
  7. #if VERBOSE
  8. #define LOG(x)    logerror x
  9. #else
  10. #define LOG(x)
  11. #endif
  12.  
  13.  
  14. /* interrupt states */
  15. static UINT8 z80_irq_enabled = 0, z8002_1_nvi_enabled = 0, z8002_2_nvi_enabled = 0;
  16.  
  17. /* ADC states */
  18. static UINT8 adc_input = 0;
  19.  
  20. /* protection states */
  21. static INT16 ic25_last_result;
  22. static UINT8 ic25_last_signed;
  23. static UINT8 ic25_last_unsigned;
  24.  
  25. /* 4-bit MCU state */
  26. static struct polepos_mcu_def
  27. {
  28.     int        enabled;            /* Enabled */
  29.     int        status;                /* Status */
  30.     int        transfer_id;        /* Transfer id */
  31.     void    *timer;                /* Transfer timer */
  32.     int        coin1_coinpercred;    /* Coinage info */
  33.     int        coin1_credpercoin;    /* Coinage info */
  34.     int        coin2_coinpercred;    /* Coinage info */
  35.     int        coin2_credpercoin;    /* Coinage info */
  36.     int        mode;                /* Mode ( 0 = read switches, 1 = Coinage, 2 = in-game ) */
  37.     int        credits;            /* Credits count */
  38.     int        start;                /* Start switch */
  39. } polepos_mcu;
  40.  
  41. /* Prototypes */
  42. static void z80_interrupt(int scanline);
  43. void polepos_sample_play(int sample); /* from sndhrdw */
  44.  
  45. /*************************************************************************************/
  46. /* Interrupt handling                                                                */
  47. /*************************************************************************************/
  48.  
  49. void polepos_init_machine(void)
  50. {
  51.     /* reset all the interrupt states */
  52.     z80_irq_enabled = z8002_1_nvi_enabled = z8002_2_nvi_enabled = 0;
  53.  
  54.     /* reset the ADC state */
  55.     adc_input = 0;
  56.  
  57.     /* reset the protection state */
  58.     ic25_last_result = 0;
  59.     ic25_last_signed = 0;
  60.     ic25_last_unsigned = 0;
  61.  
  62.     /* Initialize the MCU */
  63.     polepos_mcu.enabled = 0; /* disabled */
  64.     polepos_mcu.status = 0x10; /* ready to transfer */
  65.     polepos_mcu.transfer_id = 0; /* clear out the transfer id */
  66.     polepos_mcu.timer = 0;
  67.     polepos_mcu.start = 0;
  68.  
  69.     /* halt the two Z8002 cpus */
  70.     cpu_set_reset_line(1, ASSERT_LINE);
  71.     cpu_set_reset_line(2, ASSERT_LINE);
  72.  
  73.     /* start a timer for the Z80's interrupt */
  74.     timer_set(cpu_getscanlinetime(0), 0, z80_interrupt);
  75. }
  76.  
  77. static void z80_interrupt(int scanline)
  78. {
  79.     cpu_set_irq_line(0, 0, ((scanline & 64) == 0) ? ASSERT_LINE : CLEAR_LINE);
  80.     scanline += 64;
  81.     if (scanline >= 256) scanline = 0;
  82.     timer_set(cpu_getscanlinetime(scanline), scanline, z80_interrupt);
  83. }
  84.  
  85. WRITE_HANDLER( polepos_z80_irq_enable_w )
  86. {
  87.     z80_irq_enabled = data & 1;
  88.     if ((data & 1) == 0) cpu_set_irq_line(0, 0, CLEAR_LINE);
  89. }
  90.  
  91. WRITE_HANDLER( polepos_z8002_nvi_enable_w )
  92. {
  93.     int which = (offset / 2) + 1;
  94.  
  95.     if (which == cpu_getactivecpu())
  96.     {
  97.         if (which == 1)
  98.             z8002_1_nvi_enabled = data & 1;
  99.         else
  100.             z8002_2_nvi_enabled = data & 1;
  101.         if ((data & 1) == 0) cpu_set_irq_line(which, 0, CLEAR_LINE);
  102.     }
  103.     LOG(("Z8K#%d cpu%d_nvi_enable_w $%02x\n", cpu_getactivecpu(), which, data));
  104. }
  105.  
  106. int polepos_z8002_1_interrupt(void)
  107. {
  108.     if (z8002_1_nvi_enabled)
  109.         cpu_set_irq_line(1, 0, ASSERT_LINE);
  110.  
  111.     return ignore_interrupt();
  112. }
  113.  
  114. int polepos_z8002_2_interrupt(void)
  115. {
  116.     if (z8002_2_nvi_enabled)
  117.         cpu_set_irq_line(2, 0, ASSERT_LINE);
  118.  
  119.     return ignore_interrupt();
  120. }
  121.  
  122. WRITE_HANDLER( polepos_z8002_enable_w )
  123. {
  124.     if (data & 1)
  125.         cpu_set_reset_line(offset + 1, CLEAR_LINE);
  126.     else
  127.         cpu_set_reset_line(offset + 1, ASSERT_LINE);
  128. }
  129.  
  130.  
  131. /*************************************************************************************/
  132. /* I/O and ADC handling                                                              */
  133. /*************************************************************************************/
  134.  
  135. WRITE_HANDLER( polepos_adc_select_w )
  136. {
  137.     adc_input = data;
  138. }
  139.  
  140. READ_HANDLER( polepos_adc_r )
  141. {
  142.     int ret = 0;
  143.  
  144.     switch (adc_input)
  145.     {
  146.         case 0x00:
  147.             ret = readinputport(3);
  148.             break;
  149.  
  150.         case 0x01:
  151.             ret = readinputport(4);
  152.             break;
  153.  
  154.         default:
  155.             LOG(("Unknown ADC Input select (%02x)!\n", adc_input));
  156.             break;
  157.     }
  158.  
  159.     return ret;
  160. }
  161.  
  162. READ_HANDLER( polepos_io_r )
  163. {
  164.     int ret = 0xff;
  165.  
  166.     if (cpu_getscanline() >= 128)
  167.         ret ^= 0x02;
  168.  
  169.     ret ^= 0x08; /* ADC End Flag */
  170.  
  171.     return ret;
  172. }
  173.  
  174.  
  175. /*************************************************************************************/
  176. /* Pole Position II protection                                                       */
  177. /*************************************************************************************/
  178.  
  179. READ_HANDLER( polepos2_ic25_r )
  180. {
  181.     int result;
  182.  
  183.     offset = offset & 0x3ff;
  184.     if (offset < 0x200)
  185.     {
  186.         ic25_last_signed = (offset / 2) & 0xff;
  187.         result = ic25_last_result & 0xff;
  188.     }
  189.     else
  190.     {
  191.         ic25_last_unsigned = (offset / 2) & 0xff;
  192.         result = (ic25_last_result >> 8) & 0xff;
  193.         ic25_last_result = (INT8)ic25_last_signed * (UINT8)ic25_last_unsigned;
  194.     }
  195.  
  196.     logerror("%04X: read IC25 @ %04X = %02X\n", cpu_get_pc(), offset, result);
  197.  
  198.     return result | (result << 8);
  199. }
  200.  
  201.  
  202.  
  203. /*************************************************************************************/
  204. /* 4 bit cpu emulation                                                               */
  205. /*************************************************************************************/
  206.  
  207. WRITE_HANDLER( polepos_mcu_enable_w )
  208. {
  209.     polepos_mcu.enabled = data & 1;
  210.  
  211.     if (polepos_mcu.enabled == 0)
  212.     {
  213.         /* If its getting disabled, kill our timer */
  214.         if (polepos_mcu.timer)
  215.         {
  216.             timer_remove(polepos_mcu.timer);
  217.             polepos_mcu.timer = 0;
  218.         }
  219.     }
  220. }
  221.  
  222. static void polepos_mcu_callback(int param)
  223. {
  224.     cpu_cause_interrupt(0, Z80_NMI_INT);
  225. }
  226.  
  227. READ_HANDLER( polepos_mcu_control_r )
  228. {
  229.     if (polepos_mcu.enabled)
  230.         return polepos_mcu.status;
  231.  
  232.     return 0x00;
  233. }
  234.  
  235. WRITE_HANDLER( polepos_mcu_control_w )
  236. {
  237.     LOG(("polepos_mcu_control_w: %d, $%02x\n", offset, data));
  238.  
  239.     if (polepos_mcu.enabled)
  240.     {
  241.         if (data != 0x10)
  242.         {
  243.             /* start transfer */
  244.             polepos_mcu.transfer_id = data; /* get the id */
  245.             polepos_mcu.status = 0xe0;         /* set status */
  246.             if (polepos_mcu.timer)
  247.                 timer_remove(polepos_mcu.timer);
  248.             /* fire off the transfer timer */
  249.             polepos_mcu.timer = timer_pulse(TIME_IN_USEC(50), 0, polepos_mcu_callback);
  250.         }
  251.         else
  252.         {
  253.             /* end transfer */
  254.             if (polepos_mcu.timer) /* shut down our transfer timer */
  255.                 timer_remove(polepos_mcu.timer);
  256.             polepos_mcu.timer = 0;
  257.             polepos_mcu.status = 0x10; /* set status */
  258.         }
  259.     }
  260. }
  261.  
  262. READ_HANDLER( polepos_mcu_data_r )
  263. {
  264.     if (polepos_mcu.enabled)
  265.     {
  266.         LOG(("MCU read: PC = %04x, transfer mode = %02x, offset = %02x\n", cpu_get_pc(), polepos_mcu.transfer_id & 0xff, offset ));
  267.  
  268.         switch(polepos_mcu.transfer_id)
  269.         {
  270.             case 0x71: /* 3 bytes */
  271.                 switch (offset)
  272.                 {
  273.                     case 0x00:
  274.                         if ( polepos_mcu.mode == 0 )
  275.                             return ~( readinputport(0) ^ polepos_mcu.start ); /* Service, Gear, etc */
  276.                         else {
  277.                             static int last_in = 0;
  278.                             int in;
  279.                             static int coin1inserted;
  280.                             static int coin2inserted;
  281.  
  282.                             in = readinputport(0);
  283.  
  284.                             /* check if the user inserted a coin */
  285.                             if (polepos_mcu.coin1_coinpercred > 0)
  286.                             {
  287.                                 if ( ( last_in ^ in ) & 0x10 ) {
  288.                                     if ((in & 0x10) == 0 && polepos_mcu.credits < 99)
  289.                                     {
  290.                                         coin1inserted++;
  291.                                         if (coin1inserted >= polepos_mcu.coin1_coinpercred)
  292.                                         {
  293.                                             polepos_mcu.credits += polepos_mcu.coin1_credpercoin;
  294.                                             coin1inserted = 0;
  295.                                         }
  296.                                     }
  297.                                 }
  298.  
  299.                                 if ( ( last_in ^ in ) & 0x20 ) {
  300.                                     if ((in & 0x20) == 0 && polepos_mcu.credits < 99)
  301.                                     {
  302.                                         coin2inserted++;
  303.                                         if (coin2inserted >= polepos_mcu.coin2_coinpercred)
  304.                                         {
  305.                                             polepos_mcu.credits += polepos_mcu.coin2_credpercoin;
  306.                                             coin2inserted = 0;
  307.                                         }
  308.                                     }
  309.                                 }
  310.                             }
  311.                             else polepos_mcu.credits = 100; /* freeplay */
  312.  
  313.                             last_in = in;
  314.  
  315.                             return (polepos_mcu.credits / 10) * 16 + polepos_mcu.credits % 10;
  316.                         }
  317.                     case 0x01:
  318.                         return ~readinputport(2); /* DSW1 */
  319.                     case 0x02:
  320.                         return ~( ( readinputport(0) & 2 ) << 4 );
  321.                 }
  322.                 break;
  323.  
  324.             case 0x72: /* 8 bytes */
  325.                 switch (offset)
  326.                 {
  327.                     case 0x00: /* Steering */
  328.                         return readinputport(5);
  329.  
  330.                     case 0x04:
  331.                         return ~readinputport(1); /* DSW 0 */
  332.                 }
  333.                 break;
  334.  
  335.             case 0x91: /* 3 bytes */
  336.                 /*
  337.                    Same as 0x71 but sets coinage mode? - Program seems only to check offset 0 and make sure
  338.                    it's 0 or 0xa0 (freeplay?), otherwise, it resets itself.
  339.                 */
  340.                 case 0x00:
  341.                     polepos_mcu.mode = 1;
  342.                     if ( polepos_mcu.coin1_coinpercred > 0 )
  343.                         polepos_mcu.credits = 0;
  344.                     else
  345.                         polepos_mcu.credits = 100; /* freeplay */
  346.                     return (polepos_mcu.credits / 10) * 16 + polepos_mcu.credits % 10;
  347.                 break;
  348.  
  349.             default:
  350.                 logerror("Unknwon MCU transfer mode: %02x\n", polepos_mcu.transfer_id);
  351.                 break;
  352.         }
  353.     }
  354.  
  355.     return 0xff; /* pull up */
  356. }
  357.  
  358. WRITE_HANDLER( polepos_mcu_data_w )
  359. {
  360.     if (polepos_mcu.enabled)
  361.     {
  362.         LOG(("MCU write: PC = %04x, transfer mode = %02x, offset = %02x, data = %02x\n", cpu_get_pc(), polepos_mcu.transfer_id & 0xff, offset, data ));
  363.  
  364.         if ( polepos_mcu.transfer_id == 0xa1 ) { /* setup coins/credits, etc ( 8 bytes ) */
  365.             switch( offset ) {
  366.                 case 1:
  367.                     polepos_mcu.coin1_coinpercred = data;
  368.                     break;
  369.  
  370.                 case 2:
  371.                     polepos_mcu.coin1_credpercoin = data;
  372.                     break;
  373.  
  374.                 case 3:
  375.                     polepos_mcu.coin2_coinpercred = data;
  376.                     break;
  377.  
  378.                 case 4:
  379.                     polepos_mcu.coin2_credpercoin = data;
  380.                     break;
  381.  
  382.                 /* NOTE: I still have no clue what offset 0, 5, 6 & 7 do */
  383.             }
  384.         }
  385.  
  386.         if ( polepos_mcu.transfer_id == 0xc1 ) { /* set switch mode */
  387.             polepos_mcu.mode = 0;
  388.         }
  389.  
  390.         if ( polepos_mcu.transfer_id == 0x84 ) { /* play sample */
  391.             if ( offset == 0 ) {
  392.                 switch( data ) {
  393.                     case 0x01:
  394.                         polepos_sample_play( 0 );
  395.                     break;
  396.  
  397.                     case 0x02:
  398.                         polepos_sample_play( 1 );
  399.                     break;
  400.  
  401.                     case 0x04:
  402.                         polepos_sample_play( 2 );
  403.                     break;
  404.  
  405.                     default:
  406.                         logerror("Unknown sample triggered (%d)\n", data );
  407.                     break;
  408.                 }
  409.             }
  410.         }
  411.  
  412.         if ( polepos_mcu.transfer_id == 0x88 ) { /* play screech/explosion */
  413.             if ( offset == 0 ) {
  414.                 /* 0x40 = Start Explosion sample */
  415.                 /* 0x20 = ???? */
  416.                 /* 0x7n = Screech sound. n = pitch (if 0 then no sound) */
  417.                 if ( data == 0x40 )
  418.                     sample_start( 0, 0, 0 );
  419.  
  420.                 if ( ( data & 0xf0 ) == 0x70 ) {
  421.                     if ( ( data & 0x0f ) == 0 ) {
  422.                         if ( sample_playing(1) )
  423.                             sample_stop(1);
  424.                     } else {
  425.                         int freq = (int)( ( 44100.0f / 10.0f ) * (float)(data & 0x0f) );
  426.  
  427.                         if ( !sample_playing(1) )
  428.                             sample_start( 1, 1, 1 );
  429.                         sample_set_freq(1, freq);
  430.                     }
  431.                 }
  432.             }
  433.         }
  434.  
  435.         if ( polepos_mcu.transfer_id == 0x81 ) { /* Set coinage mode */
  436.             polepos_mcu.mode = 1;
  437.         }
  438.     }
  439. }
  440.  
  441. WRITE_HANDLER( polepos_start_w )
  442. {
  443.     static int last_start = 0;
  444.  
  445.     data &= 1;
  446.  
  447.     polepos_mcu.start = data << 2;
  448.  
  449.     /* check for start button if not in-game */
  450.     if ( polepos_mcu.mode != 2 ) {
  451.         if ( ( last_start ^ data ) && ( data == 0 ) ) {
  452.             if (polepos_mcu.credits >= 1) {
  453.                 polepos_mcu.mode = 2; /* in-game */
  454.                 polepos_mcu.credits--;
  455.             }
  456.         }
  457.     }
  458.  
  459.     last_start = data;
  460. }
  461.